/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.bmf.dao;

import com.bmf.pojo.BMFGroup;
import com.bmf.pojo.BMFNode;
import com.bmf.pojo.BMFrequest;
import com.bmf.pojo.DataIn;
import com.bmf.pojo.NewNodeIn;
import com.bmf.pojo.Notification;
import com.bmf.pojo.ToPrint;
import com.bmf.pojo.Util;
import com.bmf.rest.Group;
import common.Constants;
import common.InvalidPacketParametersException;
import communication.IBMFPacket;
import communication.IConfigurationPacket;
import communication.IPacketBuilder;
import communication.MessageBuilder;
import communication.MessageParser;
import communication.PacketBuilder;
import configurationfile.ConfigurationFileReader;
import configurationfile.IConfigurationFileReader;
import data.IDataSaver;
import data.file.FileDataSaverBuilder;
import data.file.IFileDataSaverBuilder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Observable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.tree.DefaultMutableTreeNode;
import network.manager.IBMFDataIn;
import network.manager.IBMFGroup;
import network.manager.IBMFNode;
import network.manager.INetworkBMFListener;
import network.manager.INetworkManager;
import network.manager.NetworkManager;
import network.manager.configurationPackets.ConfigurationPacketsManager;
import network.manager.configurationPackets.IConfigurationPacketsManager;
import network.manager.nodesAndGroups.BMFNodesAndGroupsManager;
import network.manager.nodesAndGroupsManager.IBMFNodesAndGroupsManager;
import network.manager.nodesAndGroupsManager.TooManyGroupsCreatedException;
import network.platform.tinyOS.TinyOSBMFManager;

/**
 *
 * @author Tony_
 */

public class HLmanager extends Observable implements Marker {
        
    private IPacketBuilder packetBuilder;
    private INetworkManager iNetworkManager;
    private IFileDataSaverBuilder iFileDataSaverBuilder;
    private IDataSaver fileDataSaver;
    private IAggregatorManager iAggregatorManager;
    private IBMFNodesAndGroupsManager iBMFNodesAndGroupsManager;
    private IConfigurationPacketsManager iConfigurationPacketsManager;
    private IConfigurationFileReader iConfigurationFileReader;
    DefaultMutableTreeNode basestation;
    private IBMFGroup d;
    
    public HLmanager() throws TooManyGroupsCreatedException{
                NetworkManager nm = new NetworkManager();
                BMFNodesAndGroupsManager bmf = new BMFNodesAndGroupsManager();
		PacketBuilder pb = new PacketBuilder();
		FileDataSaverBuilder fdsb = new FileDataSaverBuilder();
		AggregatorManager ag = new AggregatorManager();
		ConfigurationPacketsManager cpm = new ConfigurationPacketsManager();
                ConfigurationFileReader cfr = new ConfigurationFileReader();
	        setINetworkManager(nm);
                nm.setIMessageParser(new MessageParser());
		nm.setIMessageBuilder(new MessageBuilder());
		setIFileDataSaverBuilder(fdsb);
		setIAggregatorManager(ag);
		setIPacketBuilder(pb);
		setIBMFNodesAndGroupsManager(bmf);
		bmf.setINetworkManager(nm);
		bmf.setIPacketBuilder(pb);
		setIConfigurationPacketsManager(cpm);
		setIConfigurationFileReader(cfr);
		TinyOSBMFManager t = new TinyOSBMFManager();
		nm.addIPlatform(t);
                d=nm.getIBMFGroup(1, "default");
    }

    public void addGroup(Group g){
        IBMFGroup group=iNetworkManager.getIBMFGroup(Integer.parseInt(g.getId()), g.getName());       
        
    }
    public synchronized void setIConfigurationPacketsManager(
        IConfigurationPacketsManager iConfigurationPacketsManager) {
        System.out.println("IConfigurationPacketsManager was set. Thank you DS!");
        this.iConfigurationPacketsManager = iConfigurationPacketsManager;
        
    }
    public synchronized void setIConfigurationFileReader(IConfigurationFileReader iConfigurationFileReader) {
        System.out.println("IConfigurationFileReader was set. Thank you DS!");
        this.iConfigurationFileReader = iConfigurationFileReader;
        readConfigurationFile();
        basestation = new DefaultMutableTreeNode();
        basestation.setUserObject(new BMFNode(null));  
    }
    
    public boolean readConfigurationFile() {
        return this.iConfigurationFileReader.readConfigurationFile();

    }

    public synchronized void setIBMFNodesAndGroupsManager(IBMFNodesAndGroupsManager iBMFNodesAndGroupsManager) throws TooManyGroupsCreatedException {
        System.out.println("IBMFNodesAndGroupsManager was set. Thank you DS!");
        this.iBMFNodesAndGroupsManager = iBMFNodesAndGroupsManager;
    }

    public synchronized void setIPacketBuilder(IPacketBuilder packetBuilder) {
        System.out.println("IPacketBuilder was set. Thank you DS!");
        this.packetBuilder = packetBuilder;
    }

    public synchronized void setIAggregatorManager(IAggregatorManager iAggregatorManager) {
        System.out.println("IAggregatorManager was set. Thank you DS!");
        this.iAggregatorManager = iAggregatorManager;

    }

    public synchronized void setIFileDataSaverBuilder(IFileDataSaverBuilder iFileDataSaverBuilder) {
        System.out.println("IFileDataSaverBuilder was set. Thank you DS!");
        this.iFileDataSaverBuilder = iFileDataSaverBuilder;
    }

    public synchronized void setINetworkManager(INetworkManager networkManager) {
        System.out.println("INetworkManager was set. Thank you DS!");
        this.iNetworkManager = networkManager;
        this.iNetworkManager.registerListener((INetworkBMFListener) this);
    }
    
    public DefaultMutableTreeNode getBasestation() {
        return basestation;
    }
    public IPacketBuilder getPacketBuilder() {
        return packetBuilder;
    }

  
    public INetworkManager getiNetworkManager() {
        return iNetworkManager;
    }

 
    public IFileDataSaverBuilder getiFileDataSaverBuilder() {
        return iFileDataSaverBuilder;
    }

  
    public IAggregatorManager getiAggregatorManager() {
        return iAggregatorManager;
    }

   
    public IDataSaver getFileDataSaver() {
        return fileDataSaver;
    }

  
    public IBMFNodesAndGroupsManager getiBMFNodesAndGroupsManager() {
        return iBMFNodesAndGroupsManager;
    }


    public IConfigurationPacketsManager getiConfigurationPacketsManager() {
        return iConfigurationPacketsManager;
    }
    
    public void scheduleRequest() throws InvalidPacketParametersException, IOException {                                               
        // TODO add your handling code here:
        IConfigurationPacket newReq;
        newReq = this.getPacketBuilder().getIConfigurationPacket();
        newReq.setDestinationBroadcast(); //ID DESTINAZIONE
        
        //CONTROLLARE QUA
        //newReq.setDestinationGroups("1");
        
        newReq.setConfigurationType(Constants.PKT_TYPE_CONFIGURATION_SCHEDULE);
        newReq.setPeriodValue(3);
        newReq.setLifetimeValue(30);
        newReq.setPeriodTimescale(0);
        newReq.setLifetimeTimescale(0);
        newReq.setAction(0);
        newReq.setSensor_actuatorType(6); //LIGHT
        newReq.setDataType(0);
        newReq.setSyntheticData(0);
        newReq.setRequestID(0);
        BMFNode n=new BMFNode(iBMFNodesAndGroupsManager.getNodeByID(4));
        ArrayList<BMFNode> b=new ArrayList<BMFNode>();
        b.add(n);
        sendICofigurationPacket(newReq, "LIGHT", b , false);
        }


    
        
    public void sendICofigurationPacket(IConfigurationPacket newReq,String name, ArrayList<BMFNode> nodes, boolean isAggregation) throws IOException {

    	int reqID=-1;
    	if(newReq.getConfigurationType()==Constants.PKT_TYPE_CONFIGURATION_UNSCHEDULE)
    		reqID=newReq.getRequestID();
    	else reqID = this.iConfigurationPacketsManager.addIConfigurationPacket(name, newReq);
        
        BMFrequest request=new BMFrequest(this.iConfigurationPacketsManager.getIConfigurationNameByID(reqID), newReq, nodes, isAggregation);
        if (request.isAggregation()) {// se è un aggregation creo l'aggregatore
            iAggregatorManager.createIAggregator(reqID, newReq.getSyntheticData(), nodes.size());
        }
        
        //this.notifyEventToObservers(new NewRequest(request));
        //notifyEventToObservers(new ToPrint("REQUEST " + reqID + " SENT!"));
        
        new Sender(newReq).start();
        
        if (newReq.getConfigurationType() == Constants.PKT_TYPE_CONFIGURATION_SCHEDULE) {
            this.iConfigurationPacketsManager.activateIConfigurationTimerByID(
                    reqID, this);
        } else {
            this.iConfigurationPacketsManager.deactivateIConfigurationTimerByID(reqID);
        }
        System.out.println("CONFIG NAME: "
                + this.iConfigurationPacketsManager.getIConfigurationNameByID(reqID) + "  DESTINATION:"
                + newReq.getDestination());

        try {
//            this.fileDataSaver.saveIConfigurationPacket(newReq);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

    @Override
    public void newNodeInTheNetwork(IBMFNode newNode, Calendar time) {
        this.iBMFNodesAndGroupsManager.addNode(newNode);
        //try {
            //assegnare un gruppo di default
            newNode.addGroup(d);
            System.out.println("NODO AGGIUNTO AL GRUPPO DI DEFAULT!");
        //} catch (TooManyGroupsCreatedException ex) {
        //    Logger.getLogger(HLmanager.class.getName()).log(Level.SEVERE, null, ex);
        //}
        
        notifyEventToObservers(new NewNodeIn(newNode, time));
    }

    @Override
    public void newDataIn(IBMFDataIn data, Calendar time) {
        
        System.out.println("new data in");
        if (iConfigurationPacketsManager.getBMFRequestByID(data.getRequestID()) != null) {

        	long convertedData=Util.getDataConverted(data.getResult(), iConfigurationPacketsManager.getBMFRequestByID(data.getRequestID()).getSensor_actuatorType());
            notifyEventToObservers(new ToPrint("DATA RECEIVED FROM "
                    + data.getSenderID()
                    + "  Request:"
                    + iConfigurationPacketsManager.getIConfigurationNameByID(data.getRequestID())
                    + "  Result:" + convertedData));            
            try {
//                this.fileDataSaver.saveData(data.getSenderID(), data.getRequestID(), convertedData, data.getCounter());
            } catch (Exception e) {
                e.printStackTrace();
            }
           notifyEventToObservers(new DataIn(data, data.getRequestID()));
        }

    }
    
    public void notifyEventToObservers(Notification n) {
        if (n instanceof NewNodeIn) {
            System.out.println("new node in - NOTIFY TO OBSERVER");
            NewNodeIn o = (NewNodeIn) n;
            IBMFNode nodo=o.getNewNode();
            int id=nodo.getNodeID();
            this.setChanged();
            this.notifyObservers(id);
        }
        if (n instanceof DataIn) {
            System.out.println("new data in - NOTIFY TO OBSERVER");
            DataIn o = (DataIn) n;
            long data=Util.getDataConverted(o.getData().getResult(), 6);
            String s=String.valueOf(data);
            this.setChanged();
            this.notifyObservers(s);
        }
    }

    @Override
    public void ackReceived(int i, int i1, int i2, Calendar clndr) {
        //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    
    }
    @Override
    public void requestExpired(IConfigurationPacket icp) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
    
    class Sender extends Thread {

        IBMFPacket packet;

        public Sender(IBMFPacket p) {
            packet = p;
        }

        public void run() {
            try {
                iNetworkManager.sendPacket(packet);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
}
